package com.zhou.essearch.utils;

/**
 * @Author: HUANG GY.
 * @Date: 2021/6/24 16:27
 * @Description: com.zhou.essearch.utils
 */
//import com.yoke.md5util.UrlDecode;
//import com.yoke.util.file.FileUtil;

import org.springframework.data.elasticsearch.annotations.Document;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * @author jiangzeyin
 * @date 2016-9-9
 */
public class PackageUtil {


    public static void main(String[] args) throws Exception {
        List<String> fieldNameList = getItField();
        System.out.println("fieldNameList="+fieldNameList);
    }

    /**
     *  获取类的字段
     * @return
     * @throws Exception
     */
    public static  List<String> getItField() {
        List<String> fieldList = new ArrayList<>();
        try {
            System.out.println("com.zhou.essearch.document 入参");
            List<String> classNameList = getClassName("com.zhou.essearch.document");
            System.out.println("classNameList="+classNameList);
            for (String className : classNameList) {
                System.out.println("className="+className);
                className = className.replaceAll("\\\\",".");
                Class<?> clazz = Class.forName(className);
                Document documentAnnotation = clazz.getAnnotation(Document.class);
                if (documentAnnotation == null) {
                    continue;
                }
                Field[] fieldArr = clazz.getDeclaredFields();
                for (Field field : fieldArr) {
                    System.out.println("field="+field);
                    org.springframework.data.elasticsearch.annotations.Field fieldAnnotationannotation = field.getAnnotation(org.springframework.data.elasticsearch.annotations.Field.class);
                    if (fieldAnnotationannotation != null) {
                        String fieldName = field.getName();
                        fieldList.add(fieldName);
                    }
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println("fieldList="+fieldList);
        return fieldList;
    }


    /**
     * 获取某包下（包括该包的所有子包）所有类
     *
     * @param packageName 包名
     * @return 类的完整名称
     * @throws UnsupportedEncodingException
     */
    public static List<String> getClassName(String packageName) throws IOException {
        return getClassName(packageName, true);
    }

    /**
     * 获取某包下所有类
     *
     * @param packageName  包名
     * @param childPackage 是否遍历子包
     * @return 类的完整名称
     * @throws UnsupportedEncodingException
     */
    public static List<String> getClassName(String packageName, boolean childPackage) throws IOException {
        List<String> fileNames = new ArrayList<>();
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        String packagePath = packageName.replace(".", "/");
        Enumeration<URL> urls = loader.getResources(packagePath);
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            if (url == null){
                continue;
            }
            System.out.println("url = " + url);
            String type = url.getProtocol();
            System.out.println("type = " + type);
            if (type.equals("file")) {
                fileNames.addAll(getClassNameByFile(url.getPath(), childPackage));
            } else if (type.equals("jar")) {
                List<String> classNames = new ArrayList<>();
                fileNames.addAll(getClassNameByJar(url.getPath(), childPackage,packagePath));
                System.out.println("------------------------------------------");
                System.out.println("------------------------------------------");
                System.out.println("------------------------------------------");
                System.out.println("fileNames="+fileNames);
                for (String fileName : fileNames) {
                    String classes = fileName.substring(fileName.indexOf("classes") + 8);
                    System.out.println("classes="+classes);
                    classNames.add(classes);
                }
                fileNames = classNames ;

//                fileNames.addAll(getClassNameByJars(((URLClassLoader) loader).getURLs(), packagePath, childPackage));
            }
        }

        return fileNames;
    }

    /**
     * 从项目文件获取某包下所有类
     *
     * @param filePath     文件路径
     *                     类名集合
     * @param childPackage 是否遍历子包
     * @return 类的完整名称
     * @throws UnsupportedEncodingException
     */
    private static List<String> getClassNameByFile(String filePath, boolean childPackage) throws UnsupportedEncodingException {
        List<String> myClassName = new ArrayList<>();
//        filePath = UrlDecode.getURLDecode(filePath);
        File file = new File(filePath);
        File[] childFiles = file.listFiles();
        if (childFiles == null){
            return myClassName;
        }
        for (File childFile : childFiles) {
            if (childFile.isDirectory()) {
                if (childPackage) {
                    myClassName.addAll(getClassNameByFile(childFile.getPath(), childPackage));
                }
            } else {
                String childFilePath = childFile.getPath();
//                childFilePath = FileUtil.clearPath(childFilePath);
                if (childFilePath.endsWith(".class")) {
                    childFilePath = childFilePath.substring(childFilePath.indexOf("classes") + 8, childFilePath.lastIndexOf("."));
                    childFilePath = childFilePath.replace("/", ".");
                    myClassName.add(childFilePath);
                }
            }
        }
        return myClassName;
    }

    /**
     * 从jar获取某包下所有类
     *
     * @param jarPath      jar文件路径
     * @param childPackage 是否遍历子包
     * @return 类的完整名称
     * @throws UnsupportedEncodingException
     */
    private static List<String> getClassNameByJar(String jarPath, boolean childPackage,String packagePathSource) throws UnsupportedEncodingException {
        List<String> myClassName = new ArrayList<String>();
        String[] jarInfo = jarPath.split("!");
        String jarFilePath = jarInfo[0].substring(jarInfo[0].indexOf("/"));
//        jarFilePath = UrlDecode.getURLDecode(jarFilePath);
        String packagePath = jarInfo[1].substring(1);
        try {
            JarFile jarFile = new JarFile(jarFilePath);
            Enumeration<JarEntry> entrys = jarFile.entries();
            while (entrys.hasMoreElements()) {
                JarEntry jarEntry = entrys.nextElement();
                String entryName = jarEntry.getName();
                System.out.println("entryName1="+entryName);
                if (entryName.endsWith(".class")) {
                    if (childPackage) {
                        if (entryName.startsWith(packagePath)) {
                            entryName = entryName.replace("/", ".").substring(0, entryName.lastIndexOf("."));
                            System.out.println("entryName2="+entryName);
//                            entryName = entryName.substring(entryName.indexOf("classes") + 8, entryName.length() - 5);
//                            entryName = entryName.replaceAll(".","\\");
//                            System.out.println("entryName222222="+entryName);
                            myClassName.add(entryName);
                        }
                    } else {
                        int index = entryName.lastIndexOf("/");
                        String myPackagePath;
                        if (index != -1) {
                            myPackagePath = entryName.substring(0, index);
                        } else {
                            myPackagePath = entryName;
                        }
                        if (myPackagePath.equals(packagePath)) {
                            entryName = entryName.replace("/", ".").substring(0, entryName.lastIndexOf("."));
                            System.out.println("entryName3="+entryName);
                            myClassName.add(entryName);
                        }
                    }
                }
            }
        } catch (Exception e) {
            //SystemLog.Log(LogType.systemInfo, e.getMessage(), e);
        }
        return myClassName;
    }

    /**
     * 从所有jar中搜索该包，并获取该包下所有类
     *
     * @param urls         URL集合
     * @param packagePath  包路径
     * @param childPackage 是否遍历子包
     * @return 类的完整名称
     * @throws UnsupportedEncodingException
     */
    private static List<String> getClassNameByJars(URL[] urls, String packagePath, boolean childPackage) throws UnsupportedEncodingException {
        List<String> myClassName = new ArrayList<String>();
        if (urls != null) {
            for (int i = 0; i < urls.length; i++) {
                URL url = urls[i];
                String urlPath = url.getPath();
                // 不必搜索classes文件夹
                if (urlPath.endsWith("classes/")) {
                    continue;
                }
                String jarPath = urlPath + "!/" + packagePath;
                myClassName.addAll(getClassNameByJar(jarPath, childPackage,packagePath));
            }
        }
        return myClassName;
    }
}